package service

import (
	"context"
	"fx_swift_boss/api"
	"fx_swift_boss/internal/model"
	"fx_swift_boss/pkg/code"
	"fx_swift_boss/pkg/global"
	"fx_swift_boss/pkg/internalerrors"
	"fx_swift_boss/pkg/logger"
	"fx_swift_boss/pkg/page"
	"github.com/gogf/gf/v2/container/gvar"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/spf13/cast"
)

type ICommissionSrv interface {
	// 提现审核列表
	WithdrawList(ctx context.Context, req *api.WithdrawListReq) (*page.Collection[*api.WithdrawListRes], error)
	// 提现处理操作
	OperatorWithdraw(ctx context.Context, req *api.OperatorWithdrawReq) error
	// 代理商提现列表
	AgentWithdrawList(ctx context.Context, req *api.AgentWithdrawListReq) (*page.Collection[*api.AgentWithdrawListRes], error)
	// 代理商佣金账户
	AgentCommissionAccount(ctx context.Context) ([]*api.AgentCommissionAccountRes, error)
}

type commissionSrv struct {
}

func NewCommissionSrv() ICommissionSrv {
	return &commissionSrv{}
}

// 提现审核列表
func (c *commissionSrv) WithdrawList(ctx context.Context, req *api.WithdrawListReq) (*page.Collection[*api.WithdrawListRes], error) {
	var (
		err        error
		total      int
		resultList []*api.WithdrawListRes
	)
	collectionDto := &page.Collection[*api.WithdrawListRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	mod := global.GFDB.Ctx(ctx).Schema("fx").Model("fx.ifcgate_withdraw_record iwr")
	mod.LeftJoin("select image,currency,account from ifcgate_withdraw_bank_info", "iwbi.currency=iwr.currency and iwr.account=iwbi.account").As("iwbi")
	mod.Fields("iwr.company_name,iwr.amount,iwr.currency,iwbi.image,iwr.created_at,iwr.id,iwr.status")

	if len(req.CompanyName) > 0 {
		mod.WhereLike("iwr.company_name", "%"+req.CompanyName+"%")
	}
	if len(req.Status) > 0 {
		mod.Where("iwr.status=?", req.Status)
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("iwr.created_at >=? and iwr.created_at <=?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
	}
	mod.Order("iwr.created_at desc")
	mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 提现处理操作
func (c *commissionSrv) OperatorWithdraw(ctx context.Context, req *api.OperatorWithdrawReq) error {
	var (
		withdrawBankInfo *model.IfcgateWithdrawRecord
		err              error
		redisKey         string
		redisResult      *gvar.Var
		redisAmount      float64
	)
	if err = global.GFDB.Ctx(ctx).Schema("fx").Model("ifcgate_withdraw_record").
		Where("id=? and status='init'", req.Id).Scan(&withdrawBankInfo); err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if withdrawBankInfo == nil {
		return internalerrors.New(code.ErrUnknown, "该条审核记录状态异常")
	}
	redisKey = withdrawBankInfo.Account + "-" + withdrawBankInfo.Currency
	redisResult, err = g.Redis().Get(ctx, redisKey)
	if err != nil {
		logger.SugarLogger.Error(err)
		return internalerrors.New(code.ErrUnknown, err.Error())
	}
	if redisResult != nil {
		redisAmount = redisResult.Float64()
		redisAmount = redisAmount - withdrawBankInfo.Amount
		if redisAmount == 0.0 {
			if _, err = g.Redis().Del(ctx, redisKey); err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
		} else {
			if _, err = g.Redis().Set(ctx, redisKey, redisAmount); err != nil {
				logger.SugarLogger.Error(err)
				return internalerrors.New(code.ErrUnknown, err.Error())
			}
		}
	}

	if req.OperatorStr {
		if _, err = global.GFDB.Ctx(ctx).Schema("fx").Model("ifcgate_withdraw_record").
			Data(g.Map{"status": "success"}).Where("id=?", req.Id).Update(); err != nil {
			logger.SugarLogger.Error(err)
			return internalerrors.New(code.ErrUnknown, err.Error())
		}
	}
	return err
}

// 代理商提现列表
func (c *commissionSrv) AgentWithdrawList(ctx context.Context, req *api.AgentWithdrawListReq) (*page.Collection[*api.AgentWithdrawListRes], error) {
	var (
		err        error
		total      int
		resultList []*api.AgentWithdrawListRes
	)
	collectionDto := &page.Collection[*api.AgentWithdrawListRes]{}
	collectionDto.Page = uint64(req.PageNo)
	collectionDto.PageSize = uint64(req.PageSize)

	mod := global.GFDB.Ctx(ctx).Schema("fx").Model("fx.ifcgate_withdraw_record")
	mod.Fields("company_name,amount,currency,created_at,status")

	if len(req.CompanyName) > 0 {
		mod.WhereLike("company_name", "%"+req.CompanyName+"%")
	}
	if len(req.StartTime) > 0 && len(req.EndTime) > 0 {
		mod.Where("created_at >=? and created_at <=?", req.StartTime+" 00:00:00", req.EndTime+" 23:59:59")
	}
	mod.Order("created_at desc")
	mod.Limit(int(page.PageToOffset(uint64(req.PageNo), uint64(req.PageSize))), cast.ToInt(req.PageSize))
	err = mod.ScanAndCount(&resultList, &total, false)
	collectionDto.TotalPage = page.GetTotalPage(uint64(req.PageNo), uint64(req.PageSize), cast.ToInt64(total))
	if err != nil {
		return nil, internalerrors.New(code.ErrUnknown, "数据查询异常")
	}
	collectionDto.Total = cast.ToInt64(total)
	collectionDto.List = resultList

	return collectionDto, err
}

// 代理商佣金账户
func (c *commissionSrv) AgentCommissionAccount(ctx context.Context) ([]*api.AgentCommissionAccountRes, error) {
	type DbVo struct {
		Account  string  `json:"account"`
		Amount   float64 `json:"amount"`
		Currency string  `json:"currency"`
	}
	var (
		err          error
		sqlStr       string
		withdrawList []*model.IfcgateWithdrawRecord
		rList        []*api.AgentCommissionAccountInfo
		result       = make([]*api.AgentCommissionAccountRes, 0)
	)

	dbList := make([]DbVo, 0)
	sqlStr = "select SUM(a.amount) as amount,a.currency,a.account FROM " +
		"(SELECT fixed_amount as amount,fixed_currency as currency,account FROM fx.ifcgate_commission_record where account in (SELECT `account` FROM fx.`ifcgate_agent` WHERE (1=1) AND `deleted_at` IS NULL) and budget_sign = 1 and account_type='agent' " +
		"UNION ALL SELECT commission_amount as amount,commission_currency as currency,account FROM fx.ifcgate_commission_record where account in (SELECT `account` FROM fx.`ifcgate_agent` WHERE (1=1) AND `deleted_at` IS NULL) and budget_sign = 1 and account_type='agent') " +
		"a where a.currency <>'' and a.amount > 0  GROUP BY a.currency,a.account"
	err = global.GFDB.Raw(sqlStr).Scan(&dbList)

	if err = global.GFDB.Ctx(ctx).Schema("fx").Model("ifcgate_withdraw_record").
		Where("account in (SELECT `account` FROM fx.`ifcgate_agent` WHERE (1=1) AND `deleted_at` IS NULL) and status='success'").Scan(&withdrawList); err != nil {
		logger.SugarLogger.Error(err)
		return nil, internalerrors.New(code.ErrUnknown, err.Error())
	}
	currencyMap := make(map[string]float64)
	if len(withdrawList) > 0 {
		for _, value := range withdrawList {
			fAmount := cast.ToFloat64(value.Amount)
			key := value.Account + "-" + value.Currency
			if _, ok := currencyMap[key]; !ok {
				currencyMap[key] = fAmount
			} else {
				tAmount := currencyMap[key]
				currencyMap[key] = tAmount + value.Amount
			}
		}
	}
	accountMap := make(map[string][]*DbVo)
	for _, value := range dbList {
		if _, ok := accountMap[value.Account]; !ok {
			tList := make([]*DbVo, 0)
			accountMap[value.Account] = append(tList, &DbVo{
				Account:  value.Account,
				Amount:   value.Amount,
				Currency: value.Currency,
			})
		} else {
			list := accountMap[value.Account]
			accountMap[value.Account] = append(list, &DbVo{
				Account:  value.Account,
				Amount:   value.Amount,
				Currency: value.Currency,
			})
		}
	}
	for key, value := range accountMap {
		resultObj := &api.AgentCommissionAccountRes{}
		resultObj.Account = key
		rList = make([]*api.AgentCommissionAccountInfo, 0)
		for _, obj := range value {
			rList = append(rList, &api.AgentCommissionAccountInfo{
				Amount:   cast.ToString(obj.Amount),
				Currency: obj.Currency,
			})
		}
		resultObj.AgentCommissionAccountInfo = rList
		result = append(result, resultObj)
	}
	return result, err
}
